package com.finch.interview;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Levi Wang
 * @create 2021-07-27 20:11
 *
 * 如何实现一个阻塞队列？
 *
 */

public class SelfBlockingQueue<T> {

    private Object[] items;
    private int addPosition, removePosition,count;
    private Lock lock = new ReentrantLock();
    private Condition full = lock.newCondition();
    private Condition empty = lock.newCondition();

    private SelfBlockingQueue(int size) {
        this.items = new Object[size];
    }

    public void add(T t){
        lock.lock();

        try {
            while (count == items.length) {
                full.await();
                System.out.println("队列已满");
            }
            items[addPosition] = t;
            if (++addPosition == items.length) {
                addPosition = 0;
            }
            count++;
            empty.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public T remove() throws InterruptedException {
        T t1;
        lock.lock();
        try {
            while (count == 0) {
                empty.await();
                System.out.println("对列为空");
            }
            Object t = items[removePosition];
            if (++removePosition == items.length) {
                removePosition = 0;
            }
            count--;
            full.signal();
            return (T) t;
        }finally {
            lock.unlock();
        }

    }


    public static void main(String[] args)  {
        SelfBlockingQueue<Integer> blockingQueue = new SelfBlockingQueue<>(8);
        for (int i = 0; i < 20; i++) {
            int j = i;
            new Thread( () -> {
                try {
                    blockingQueue.add(Integer.valueOf(j));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 20; i++) {
            new Thread( () -> {
                try {
                    blockingQueue.remove();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
//        blockingQueue.add(1);
//        System.out.println(blockingQueue.remove());

    }


}

















